package gsd.gaudi.client.recorder;

import gsd.gaudi.common.GaudiException;
import gsd.gaudi.common.GaudiGuiHierarchy;
import gsd.gaudi.common.GaudiReport;
import gsd.gaudi.common.model.log.GaudiListener;
import gsd.gaudi.common.model.log.GaudiListenerSequence;

import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;

public class GaudiListenerRecorder extends GaudiRecorder{

	private ListenerMonitor monitor;
	private EventMonitor emonitor;
	private EventMonitor eventmonitor;
	private GaudiListenerSequence sequence;
	private GaudiGuiHierarchy hierarchy;
	
	private int nevents;
	
	private GaudiListener currentListener = null;
	private String lastWidgetClicked = "";
	
	public GaudiListenerRecorder(String name) {
		super(name);
		this.nevents = 0;
		ListenerMonitor.setRecorder(this);
		setEmonitor(new EventMonitor(this));
		this.setEventmonitor(new EventMonitor(this));
		this.hierarchy = new GaudiGuiHierarchy();
	}

	public void startRecording(){
		super.startRecording();
		this.hierarchy.processGUI();
		this.sequence = new GaudiListenerSequence();
	}
	
	public void startListener(String listener){
		System.out.println("-->Start Listener " + listener);
		this.currentListener = new GaudiListener("noideia", listener);
	}
	
	public void endListener(String listener){
		System.out.println("-->End Listener " + listener);
		if(this.currentListener == null)
			this.sequence.addListener(new GaudiListener("noidea", listener));
		else
			this.sequence.addListener(this.currentListener);
		this.currentListener = null;
	}
	
	public void addReadAccessToCurrentListener(String type, Object component, Object value){
		
		if(this.currentListener == null || !(value instanceof Serializable)){
			return;
		}
		
		String id = this.hierarchy.findWidgetId((Component)component);
		System.out.println("-->Read value " + value + " from "+ id);
		this.currentListener.addAccess(id, (Serializable)value, false, true);
	}
	
	public void addWriteAccessToCurrentListener(String type, Object component, Object value){
		
		System.out.println("-->Write value "); 
		
		if (this.currentListener == null || value == null || !(value instanceof Serializable)){
			return;
		}
		
		String id = this.hierarchy.findWidgetId((Component)component);
		System.out.println("-->Write value " + value + " to "+ id);
		this.currentListener.addAccess(id, (Serializable)value, true, false);
	}
	
	public void processEvent(AWTEvent e) {
		
		this.nevents++;
		
		if(e.getID() == WindowEvent.WINDOW_ACTIVATED && !this.lastWidgetClicked.equals("")){	
			if (this.hierarchy.findWidgetId((Component) e.getSource()) == null &&
				this.hierarchy.findWidget(this.lastWidgetClicked  + "/0") == null){
				
				this.hierarchy.processWidget((Component) e.getSource(), this.lastWidgetClicked + "/0");
				
			}else if (this.hierarchy.findWidgetId((Component) e.getSource()) == null &&
					  this.hierarchy.findWidget(this.lastWidgetClicked + "/0") != null){
				
				this.hierarchy.updateWidget((Component) e.getSource(), this.lastWidgetClicked + "/0");
			}
		}else if (e.getID() == MouseEvent.MOUSE_PRESSED){
			String s = this.hierarchy.findWidgetId((Component) e.getSource());
			if(s != null){
				this.lastWidgetClicked = s;
			}
		}
		
	}
	
	public void recordEventSequence(Exception e) {
		if(!this.recording)
			return;
		
		if(this.currentListener != null)
			this.sequence.addListener(this.currentListener);
		
		this.stopRecording();
		
		System.out.println("[GaudiListenerRecorder]-Recording run to file...");
		
		(new File("gaudi")).mkdir();
		(new File("./gaudi/listenerlogs")).mkdir();
		
		String filename = "./gaudi/listenerlogs/" + this.name + this.timelastevent + ".txt";
		
		GaudiReport report = new GaudiReport(this.sequence, new GaudiException(e));
		
		try{
			OutputStream file = new FileOutputStream(filename);
		    OutputStream buffer = new BufferedOutputStream(file);
		    ObjectOutput output = new ObjectOutputStream(buffer);
		    output.writeObject(report);
			output.close();
		}catch (Exception e1){
			System.err.println("Error: " + e1.getMessage());
		}
		
		System.out.println("[GaudiEventRecorder]-run recorded in file: " + filename);
		System.out.println("[GaudiEventRecorder]-User triggered " + this.nevents + " events.");
		System.out.println("[GaudiEventRecorder]-Recorded " + this.sequence.getListenerseq().size() + " listeners.");
		
	}
	
	public void printSequence(){
		System.out.println(this.sequence);
	}

	public void setMonitor(ListenerMonitor monitor) {
		this.monitor = monitor;
	}

	public ListenerMonitor getMonitor() {
		return monitor;
	}

	public void setEmonitor(EventMonitor emonitor) {
		this.emonitor = emonitor;
	}

	public EventMonitor getEmonitor() {
		return emonitor;
	}

	public void setEventmonitor(EventMonitor eventmonitor) {
		this.eventmonitor = eventmonitor;
	}

	public EventMonitor getEventmonitor() {
		return eventmonitor;
	}

	

}
